~ chicken-core (master) /manual/Module (chicken condition)
Trap1[[tags: manual]]
2[[toc:]]
3
4== Module (chicken condition)
5
6This module provides various procedures and special forms for raising
7and handling exceptions with "condition objects". Condition objects
8provide a structured and composable way to encode the kind of
9exception that took place, and provide the necessary context.
10
11CHICKEN's exception handling is based on the
12[[http://srfi.schemers.org/srfi-12/srfi-12.html|SRFI-12]] exception
13system. This document contains the core of the SRFI-12 spec as well
14as CHICKEN implementation specifics.
15
16There is also a {{srfi-12}} or {{(srfi 12)}} module which only
17includes the standard procedures and macros from the SRFI document,
18without the CHICKEN extensions. {{(chicken condition)}} offers the
19complete set of procedures and macros, both CHICKEN-specific and
20standard SRFI-12.
21
22
23== CHICKEN implementation
24
25=== System conditions
26
27All error-conditions signaled by the system are of kind {{exn}}.
28The following composite conditions are additionally defined:
29
30<table>
31
32<tr><td> (exn arity) </td><td>
33
34Signaled when a procedure is called with the wrong number of arguments.
35
36</td></tr><tr><td> (exn type) </td><td>
37
38Signaled on type-mismatch errors, for example when an argument of the wrong
39type is passed to a built-in procedure.
40
41</td></tr><tr><td> (exn arithmetic) </td><td>
42
43Signaled on arithmetic errors, like division by zero.
44
45</td></tr><tr><td> (exn i/o) </td><td>
46
47Signaled on input/output errors.
48
49</td></tr><tr><td> (exn i/o file) </td><td>
50
51Signaled on file-related errors.
52
53</td></tr><tr><td> (exn i/o net) </td><td>
54
55Signaled on network errors.
56
57</td></tr><tr><td> (exn bounds) </td><td>
58
59Signaled on errors caused by accessing non-existent elements of a collection.
60
61</td></tr><tr><td> (exn runtime) </td><td>
62
63Signaled on low-level runtime-system error-situations.
64
65</td></tr><tr><td> (exn runtime limit) </td><td>
66
67Signaled when an internal limit is exceeded (like running out of memory).
68
69</td></tr><tr><td> (exn match) </td><td>
70
71Signaled on errors raised by failed matches (see the section on {{match}}).
72
73</td></tr><tr><td> (exn syntax) </td><td>
74
75Signaled on syntax errors.
76
77</td></tr>
78
79</table>
80
81=== Notes
82
83* All error-exceptions (of the kind {{exn}}) are non-continuable.
84
85* Error-exceptions of the {{exn}} kind have additional {{arguments}} and
86{{location}} properties that contain the arguments passed to the
87exception-handler and the name of the procedure where the error occurred (if
88available).
89
90* Within the interpreter (csi), a user-interrupt ({{signal/int}}) signals an
91exception of the kind {{user-interrupt}}.
92
93* The procedure {{condition-property-accessor}} accepts an optional third
94argument. If the condition does not have a value for the desired property and
95if the optional argument is given, no error is signaled and the accessor
96returns the third argument.
97
98* On platforms that support the {{sigprocmask(3)}} POSIX API function,
99the signals {{SIGSEGV}}, {{SIGFPE}}, {{SIGBUS}} and {{SIGILL}} will be
100caught and trigger an exception instead of aborting the process, if
101possible. If the unwinding and handling of the signal raises one of
102these signals once again, the process will abort with an error
103message.
104
105* New in CHICKEN 5.4.0: condition objects produced by procedures that
106change errno have an {{errno}} property. To access it, use
107{{(get-condition-property <the-condition-object> 'exn 'errno)}}.
108
109=== Additional API
110
111==== condition-case
112
113<macro>(condition-case EXPRESSION CLAUSE ...)</macro>
114
115Evaluates {{EXPRESSION}} and handles any exceptions that are covered by
116{{CLAUSE ...}}, where {{CLAUSE}} should be of the following form:
117
118 CLAUSE = ([VARIABLE] (KIND ...) BODY ...)
119
120If provided, {{VARIABLE}} will be bound to the signaled exception
121object. {{BODY ...}} is executed when the exception is a property-
122or composite condition with the kinds given {{KIND ...}} (unevaluated).
123If no clause applies, the exception is re-signaled in the same dynamic
124context as the {{condition-case}} form.
125
126<enscript highlight=scheme>
127(define (check thunk)
128 (condition-case (thunk)
129 [(exn file) (print "file error")]
130 [(exn) (print "other error")]
131 [var () (print "something else")] ) )
132
133(check (lambda () (open-input-file ""))) ; -> "file error"
134(check (lambda () some-unbound-variable)) ; -> "othererror"
135(check (lambda () (signal 99))) ; -> "something else"
136
137(condition-case some-unbound-variable
138 ((exn file) (print "ignored")) ) ; -> signals error
139</enscript>
140
141==== get-condition-property
142
143<procedure>(get-condition-property CONDITION KIND PROPERTY [DEFAULT])</procedure>
144
145A slightly more convenient condition property accessor, equivalent to
146
147 ((condition-property-accessor KIND PROPERTY [DEFAULT]) CONDITION)
148
149==== condition
150
151<procedure>(condition LST1 LST2 ...)</procedure>
152
153This is a more convenient constructor for conditions. Each of
154{{LST1}}, {{LST2}} etc is a list of the following form:
155
156 (KIND PROPERTY1 VALUE1 PROPERTY2 VALUE2 ...)
157
158In other words, the following:
159
160 (signal (condition '(exn location foo message "hi") '(file bar 1)))
161
162is equivalent to the SRFI-12 code:
163
164 (signal (make-composite-condition
165 (make-property-condition 'exn 'location 'foo 'message "hi")
166 (make-property-condition 'file 'bar 2)))
167
168
169==== condition->list
170
171<procedure>(condition->list CONDITION)</procedure>
172
173This procedure converts a condition object into a list holding all the
174conditions that are represented by the ''CONDITION'' object. It is
175formatted as follows:
176
177 ((KIND1 PROPERTY1 VALUE1 PROPERTY2 VALUE2 ...) (KIND2 ... ) ... )
178
179There is no guaranteed order within the list.
180
181
182==== print-error-message
183
184<procedure>(print-error-message EXN [PORT [HEADER]])</procedure>
185
186Prints an appropriate error message to {{PORT}} (which defaults to the
187value of {{(current-output-port)}} for the object {{EXN}}. {{EXN}} may
188be a condition, a string or any other object. The output is prefixed
189by the {{HEADER}}, which defaults to {{"Error:"}}.
190
191
192
193== SRFI-12 specification
194
195A Scheme implementation ("the system") raises an exception whenever an
196error is to be signaled or whenever the system determines that evaluation
197cannot proceed in a manner consistent with the semantics of Scheme. A
198program may also explicitly raise an exception.
199
200Whenever the system raises an exception, it invokes the current exception
201handler with a condition object (encapsulating information about the
202exception) as its only argument. Any procedure accepting one argument
203may serve as an exception handler. When a program explicitly raises an
204exception, it may supply any object to the exception handler.
205
206An exception is either continuable or non-continuable. When the current
207exception handler is invoked for a continuable exception, the continuation
208uses the handler's result(s) in an exception-specific way to continue.
209When an exception handler is invoked for a non-continuable exception,
210the continuation raises a non-continuable exception indicating that the
211exception handler returned. On CHICKEN, system error exceptions
212(of kind {{exn}}) are non-continuable.
213
214=== Exception Handlers
215
216==== current-exception-handler
217
218<parameter>(current-exception-handler [PROCEDURE])</parameter><br>
219
220Sets or returns the current exception handler, a procedure of one
221argument, the exception object.
222
223==== with-exception-handler
224
225<procedure>(with-exception-handler handler thunk)</procedure><br>
226
227Returns the result(s) of invoking ''thunk''. The ''handler'' procedure
228is installed as the current exception handler in the dynamic context of
229invoking ''thunk''.
230
231Example:
232
233<enscript highlight=scheme>
234(call-with-current-continuation
235 (lambda (k)
236 (with-exception-handler (lambda (x) (k '()))
237 (lambda () (car '())))))
238;=> '()
239</enscript>
240
241Note that the handler procedure must somehow return non-locally out of
242the dynamic extent of the {{with-exception-handler}} form, because
243returning normally will signal yet another exception and thus result
244in non-termination.
245
246==== handle-exceptions
247
248<macro>(handle-exceptions var handle-expr expr1 expr2 ...)</macro><br>
249
250Evaluates the body expressions ''expr1'', ''expr2'', ... in sequence with
251an exception handler constructed from ''var'' and ''handle-expr''. Assuming
252no exception is raised, the result(s) of the last body expression is(are)
253the result(s) of the {{handle-exceptions}} expression.
254
255The exception handler created by {{handle-exceptions}} restores the dynamic
256context (continuation, exception handler, etc.) of the {{handle-exceptions}}
257expression, and then evaluates ''handle-expr'' with ''var'' bound to the
258value provided to the handler.
259
260Examples:
261
262<enscript highlight=scheme>
263(handle-exceptions exn
264 (begin
265 (display "Went wrong")
266 (newline))
267 (car '()))
268; displays "Went wrong"
269
270(handle-exceptions exn
271 (cond
272 ((eq? exn 'one) 1)
273 (else (abort exn)))
274 (case (random 3)
275 [(0) 'zero]
276 [(1) (abort 'one)]
277 [else (abort "Something else")]))
278;=> 'zero, 1, or (abort "Something else")
279</enscript>
280
281=== Raising Exceptions
282
283==== abort
284
285<procedure>(abort obj)</procedure><br>
286
287Raises a non-continuable exception represented by ''obj''. The {{abort}}
288procedure can be implemented as follows:
289
290<enscript highlight=scheme>
291(define (abort obj)
292 ((current-exception-handler) obj)
293 (abort (make-property-condition
294 'exn
295 'message
296 "Exception handler returned")))
297</enscript>
298
299The {{abort}} procedure does not ensure that its argument is a condition.
300If its argument is a condition, {{abort}} does not ensure that the condition
301indicates a non-continuable exception.
302
303==== signal
304
305<procedure>(signal obj)</procedure><br>
306
307Raises a continuable exception represented by ''obj''. The {{signal}} procedure
308can be implemented as follows:
309
310<enscript highlight=scheme>
311(define (signal exn)
312 ((current-exception-handler) exn))
313</enscript>
314
315The {{signal}} procedure does not ensure that its argument is a condition.
316If its argument is a condition, {{signal}} does not ensure that the condition
317indicates a continuable exception.
318
319=== Condition Objects
320
321==== condition?
322
323<procedure>(condition? obj)</procedure><br>
324
325Returns #t if ''obj'' is a condition, otherwise returns #f.
326
327Rationale: Any Scheme object may be passed to an exception handler. This
328would cause ambiguity if conditions were not disjoint from all of Scheme's
329standard types.
330
331==== make-property-condition
332
333<procedure>(make-property-condition kind-key prop-key value ...)</procedure><br>
334
335This procedure accepts any even number of arguments after ''kind-key'',
336which are regarded as a sequence of alternating ''prop-key'' and ''value''
337objects. Each ''prop-key'' is regarded as the name of a property, and
338each ''value'' is regarded as the value associated with the ''key'' that
339precedes it. Returns a ''kind-key'' condition that associates the given
340''prop-key''s with the given ''value''s.
341
342==== make-composite-condition
343
344<procedure>(make-composite-condition condition ...)</procedure><br>
345
346Returns a newly-allocated condition whose components correspond to the
347given ''condition''s. A predicate created by {{condition-predicate}} returns
348true for the new condition if and only if it returns true for one or more
349of its component conditions.
350
351==== condition-predicate
352
353<procedure>(condition-predicate kind-key)</procedure><br>
354
355Returns a predicate that can be called with any object as its argument.
356Given a condition that was created by {{make-property-condition}}, the
357predicate returns #t if and only if ''kind-key'' is EQV? to the kind key
358that was passed to {{make-property-condition}}. Given a composite condition
359created with {{make-composite-condition}}, the predicate returns #t if and only
360if the predicate returns #t for at least one of its components.
361
362==== condition-property-accessor
363
364<procedure>(condition-property-accessor kind-key prop-key [default])</procedure><br>
365
366Returns a procedure that can be called with any condition that satisfies
367{{(condition-predicate ''kind-key'')}}. Given a condition that was created
368by {{make-property-condition}} and ''kind-key'', the procedure returns the
369value that is associated with ''prop-key''. Given a composite condition
370created with {{make-composite-condition}}, the procedure returns the value that
371is associated with ''prop-key'' in one of the components that satisfies
372{{(condition-predicate ''kind-key'')}}.
373
374On CHICKEN, this procedure accepts an optional third argument
375DEFAULT. If the condition does not have a value for the desired
376property and if the optional argument is given, no error is signaled
377and the accessor returns the third argument.
378
379When the system raises an exception, the condition it passes to the
380exception handler includes the {{'exn}} kind with the following
381properties:
382
383; message : the error message
384; arguments: the arguments passed to the exception handler
385; location: the name of the procedure where the error occurred (if available)
386
387Thus, if ''exn'' is a condition representing a system exception,
388then
389
390<enscript highlight=scheme>
391 ((condition-property-accessor 'exn 'message) exn)
392</enscript>
393
394extracts the error message from ''exn''. Example:
395
396<enscript highlight=scheme>
397(handle-exceptions exn
398 (begin
399 (display "Went wrong: ")
400 (display
401 ((condition-property-accessor 'exn 'message) exn))
402 (newline))
403 (car '()))
404; displays something like "Went wrong: can't take car of nil"
405</enscript>
406
407=== More Examples
408
409<enscript highlight=scheme>
410(define (try-car v)
411 (let ((orig (current-exception-handler)))
412 (with-exception-handler
413 (lambda (exn)
414 (orig (make-composite-condition
415 (make-property-condition
416 'not-a-pair
417 'value
418 v)
419 exn)))
420 (lambda () (car v)))))
421
422(try-car '(1))
423;=> 1
424
425(handle-exceptions exn
426 (if ((condition-predicate 'not-a-pair) exn)
427 (begin
428 (display "Not a pair: ")
429 (display
430 ((condition-property-accessor 'not-a-pair 'value) exn))
431 (newline))
432 (abort exn))
433 (try-car 0))
434; displays "Not a pair: 0"
435
436(let* ((cs-key (list 'color-scheme))
437 (bg-key (list 'background))
438 (color-scheme? (condition-predicate cs-key))
439 (color-scheme-background
440 (condition-property-accessor cs-key bg-key))
441 (condition1 (make-property-condition cs-key bg-key 'green))
442 (condition2 (make-property-condition cs-key bg-key 'blue))
443 (condition3 (make-composite-condition condition1 condition2)))
444 (and (color-scheme? condition1)
445 (color-scheme? condition2)
446 (color-scheme? condition3)
447 (color-scheme-background condition3)))
448; => 'green or 'blue
449</enscript>
450
451----
452Previous: [[Module (chicken bytevector)]]
453
454Next: [[Module (chicken continuation)]]